package com.xyx.uniplugin_bloodoxygen.device;

import android.util.Log;

import com.xyx.uniplugin_bloodoxygen.interfaces.IDataFilter;
import com.xyx.xyxandwxx_ble.async.IAction;
import com.xyx.xyxandwxx_ble.enums.DeviceState;
import com.xyx.xyxandwxx_ble.interfaces.IDevice;

import java.util.HashSet;

/**
 * 血氧设备
 */
public class BloodDevice {
    private static final String TAG = "BloodDevice";
    /**
     * 蓝牙设备
     */
    public IDevice device;
    /**
     * 包头
     */
    private final byte[] headers = new byte[]{ (byte)0xAA, 0x55 };
    /**
     * 注册过滤器
     */
    private HashSet<IDataFilter> dataFilters = new HashSet<>();
    /**
     * 数据位的偏移位置
     */
    private static final int dataOffset = 4;

    /**
     * 构造函数
     * @param device 设备
     */
    public BloodDevice(IDevice device){
        this.device = device;
        this.device.setOnReceiveMessage(this::onMessageReceive);
    }

    /**
     * 添加过滤器
     * @param dataFilter  过滤器
     */
    public void addFilter(IDataFilter dataFilter) {
        if(this.dataFilters.contains(dataFilter))return;
        this.dataFilters.add(dataFilter);
    }

    /**
     * 单独获取数据数组
     * @param buffer 原始数据
     * @return 数据数组
     */
    private byte[] getDataArray(byte[] buffer) {
        byte[] target = new byte[buffer.length - 5];

        for(int i = dataOffset; i < buffer.length - 1; i ++) {
            target[i - dataOffset] = buffer[i];
        }
        return target;
    }

    /**
     * 是否已经连接了
     * @return 是否连接
     */
    public boolean isConnected(){
        return device.getDeviceState() == DeviceState.connected;
    }

    /**
     * 打印数据
     * @param buffer 数据
     */
    public static void printBuffer(byte[] buffer) {
        String content = "";
        for(byte item : buffer){
            content += " 0x" + Integer.toHexString(item);
        }
        Log.i(TAG, String.format("接收到数据内容 : %s", content));
    }

    /**
     * 接收数据
     * @param buffer 数据数组
     */
    private void onMessageReceive(byte[] buffer) {
        try{
            printBuffer(buffer);

            if(buffer[0] != headers[0] || buffer[1] != headers[1]) {
                return;
            }

            byte token = buffer[2];

            byte[] datas = getDataArray(buffer);
            for(IDataFilter filter : dataFilters) {
                if(filter.isOK(token, buffer[3], datas)){
                    filter.onMessageReceive(datas);
                    break;
                }
            }

        }catch (Exception e){
            e.printStackTrace();
        }
    }

    /**
     * 计算crc8-maxim
     * @param source 数据buffer
     * @param offset 起始位置
     * @param length 数据长度
     * @return 计算后的校验值
     */
    private static int cRC8MAXIM(byte[] source, int offset, int length) {
        int wCRCin = 0x00;
        // Integer.reverse(0x31) >>> 24
        int wCPoly = 0x8C;
        for (int i = offset, cnt = offset + length; i < cnt; i++) {
            wCRCin ^= ((long) source[i] & 0xFF);
            for (int j = 0; j < 8; j++) {
                if ((wCRCin & 0x01) != 0) {
                    wCRCin >>= 1;
                    wCRCin ^= wCPoly;
                } else {
                    wCRCin >>= 1;
                }
            }
        }
        return wCRCin ^= 0x00;
    }

    /**
     * 计算crc8的校验
     * @param buffer 数据buffer
     */
    public void calCrc8(byte[] buffer) {
        int value = cRC8MAXIM(buffer, 0, buffer.length - 1);
        buffer[buffer.length - 1] = (byte)value;
    }

    /**
     * 监听血氧参数
     * @return 是否开启成功
     * @exception Exception 打开异常
     */
    public void openListenBloodOxygenParam(IAction.ActionOne<Boolean> res) throws Exception {
        byte[] buffer = new byte[]{ headers[0], headers[1], 0x0F, 0x03, (byte)0x84, 0x01, 0x00 };
        calCrc8(buffer);
        // 发送启动血氧参数数据
        device.sendMessage(buffer).setTaskResultRun(res);
    }

    /**
     * 关闭血氧参数的监听
     * @return 是否关闭成功
     * @exception Exception 异常
     */
    public void closeListenBloodOxygenParam(IAction.ActionOne<Boolean> res) throws Exception {
        byte[] buffer = new byte[]{ headers[0], headers[1], 0x0F, 0x03, (byte)0x84, 0x00, 0x00 };
        calCrc8(buffer);
        // 发送启动血氧参数数据
        device.sendMessage(buffer).setTaskResultRun(res);
    }

    /**
     * 打开波形数据上传
     * @return 是否打开成功
     * @exception Exception 打开异常
     */
    public void openWaveFormData(IAction.ActionOne<Boolean> res) throws Exception {
        byte[] buffer = new byte[]{ headers[0], headers[1], 0x0F, 0x03, (byte)0x85, 0x01, 0x00 };
        calCrc8(buffer);
        // 发送启动血氧参数数据
        device.sendMessage(buffer).setTaskResultRun(res);
    }

    /**
     * 打开波形数据上传
     * @return 是否打开成功
     * @exception Exception 打开异常
     */
    public void closeWaveFormData(IAction.ActionOne<Boolean> res) throws Exception {
        byte[] buffer = new byte[]{ headers[0], headers[1], 0x0F, 0x03, (byte)0x85, 0x00, 0x00 };
        calCrc8(buffer);
        // 发送启动血氧参数数据
        device.sendMessage(buffer).setTaskResultRun(res);
    }

    /**
     * 连接设备
     * @param serverId 服务id
     * @param writeId 写入服务id
     * @param readId 读取服务id
     * @return 是否连接成功
     */
    public void connect(String serverId, String writeId, String readId, IAction.ActionOne<Boolean> callback) throws Exception {
        try {
            device.connect(serverId, writeId, readId).setTaskResultRun(callback);
        } catch (Exception e) {
            e.printStackTrace();
            callback.action(false);
        }
    }
}
